package xyz.csmcool.imoss.service.impl;

import io.minio.CreateMultipartUploadResponse;
import io.minio.ListPartsResponse;
import io.minio.MinioClient;
import io.minio.errors.*;
import io.minio.messages.Part;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import xyz.csmcool.imoss.config.PearlMinioClient;
import xyz.csmcool.imoss.entity.OssConfig;
import xyz.csmcool.imoss.mapper.OssConfigMapper;
import xyz.csmcool.imoss.service.FileUploadService;
import xyz.csmcool.imoss.template.MinioTemplate;
import xyz.csmcool.imoss.utils.NameUtil;
import xyz.csmcool.imutil.ExceptionHandler.CommonException;
import xyz.csmcool.imutil.webVo.ResultCode;

import java.io.File;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 什锦
 * @Package xyz.csmcool.imoss.service.impl
 * @since 2022/8/5 14:11
 */

@Service
@RequiredArgsConstructor
public class FileUploadServiceImpl implements FileUploadService {

    final OssConfigMapper ossConfigMapper;
    final TencentUpload tencentUpload;
    final FastdfsUpload fastdfsUpload;
    final AliUpload aliUpload;
    final HuaweiUpload huaweiUpload;
    final MinIoUpload minIoUpload;



    @Override
    public String upload(MultipartFile multipartFile,String prefix) {
        // 获取文件名
        String fileName = multipartFile.getOriginalFilename();
        // 获取文件后缀
        String hou = fileName.substring(fileName.lastIndexOf("."));
        try {
            File file = File.createTempFile(System.currentTimeMillis() + "", hou);
            multipartFile.transferTo(file);
            return this.upload(file, prefix);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public String upload(File file,String prefix) {
        Integer ossType = ossConfigMapper.getOssType();
        String result = null;
        if (ossType == null) {
            return null;
        }
        if (ossType == 1) {
            result = fastdfsUpload.upload(file, prefix);
        }

        if (ossType == 2) {
            result = tencentUpload.upload(file, prefix);
        }

        if (ossType == 3) {
            result = aliUpload.upload(file, prefix);
        }

        if (ossType == 4) {
            result = huaweiUpload.upload(file, prefix);
        }

        if (ossType == 5) {
            result = minIoUpload.upload(file, prefix);
        }
        if (file.exists()) {
            file.delete();
        }
        return result;
    }

    /**
     * 分片url获取
     *
     * @param filename
     * @param size
     * @return
     */
    @Override
    public Map<String, Object> createMultipartUpload(String filename, Integer size) {
        OssConfig ossConfig = ossConfigMapper.selectConfig();
        MinioClient minioClient =
                MinioClient.builder()
                        .endpoint(ossConfig.getRegion())
                        .credentials(ossConfig.getSecretId(), ossConfig.getSecretKey())
                        .build();

        PearlMinioClient pearlMinioClient = new PearlMinioClient(minioClient);
        MinioTemplate minioTemplate = new MinioTemplate(pearlMinioClient,ossConfig);

        String fileName = ossConfig.getPrefix() + "roomOtherFile/" + NameUtil.generateUniqueName(filename);

        // 1. 根据文件名创建签名
        Map<String, Object> result = new HashMap<>();
        // 2. 获取uploadId
        try {
            CreateMultipartUploadResponse response = minioTemplate.uploadId(
                    ossConfig.getBucketName(), null, fileName, null, null);
            String uploadId = response.result().uploadId();
            result.put("uploadId", uploadId);
            result.put("fileName",fileName);

            // 3. 请求Minio 服务，获取每个分块带签名的上传URL
            Map<String, String> reqParams = new HashMap<>();
            reqParams.put("uploadId", uploadId);
            // 4. 循环分块数 从1开始
            for (int i = 1; i <= size; i++) {
                reqParams.put("partNumber", String.valueOf(i));
                // 获取URL
                String uploadUrl = minioTemplate.getPresignedObjectUrl(ossConfig.getBucketName(), fileName, reqParams);
                // 添加到集合
                result.put("chunk_" + (i - 1), uploadUrl);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new CommonException(ResultCode.CUSTOM_FAIL.setMessage("获取url失败"));
        }
        return result;
    }

    /**
     * 完成上传
     *
     * @param objectName
     * @param uploadId
     */
    @Override
    public String completeMultipartUpload(String objectName, String uploadId) {
        OssConfig ossConfig = ossConfigMapper.selectConfig();
        MinioClient minioClient =
                MinioClient.builder()
                        .endpoint(ossConfig.getRegion())
                        .credentials(ossConfig.getSecretId(), ossConfig.getSecretKey())
                        .build();

        PearlMinioClient pearlMinioClient = new PearlMinioClient(minioClient);
        MinioTemplate minioTemplate = new MinioTemplate(pearlMinioClient,ossConfig);

        try {
            Part[] parts = new Part[10000];
            ListPartsResponse partResult = minioTemplate.listMultipart(ossConfig.getBucketName(), null, objectName, 1000, 0, uploadId, null, null);
            int partNumber = 1;
            System.err.println(partResult.result().partList().size() + "========================");
            for (Part part : partResult.result().partList()) {
                parts[partNumber - 1] = new Part(partNumber, part.etag());
                partNumber++;
            }
            minioTemplate.completeMultipartUpload(ossConfig.getBucketName(), null, objectName, uploadId, parts, null, null);
        } catch (Exception e) {
            e.printStackTrace();
            throw new CommonException(ResultCode.CUSTOM_FAIL.setMessage("合并文件失败"));
        }
        return ossConfig.getUrl() + "/" + ossConfig.getBucketName() + "/" + objectName;
    }
}
